#ifndef _COMPILATION_EXPRESSION_VISITOR_H_
#define _COMPILATION_EXPRESSION_VISITOR_H_

#include <compilation/instruction/Visitor.h>
#include <compilation/instruction/Expression.h>

#ifndef NDEBUG
#define DEBUG_EXPRESSION_VISITOR \
  if (::compilation::debug_expression_visitor) \
  std::cout << "  "
#else
#define DEBUG_EXPRESSION_VISITOR \
  if (false) std::cout
#endif // NDEBUG

namespace compilation
{

#ifndef NDEBUG
  extern bool debug_expression_visitor;
#else
  static constexpr bool debug_expression_visitor = false;
#endif // NDEBUG

template <typename _Return, typename... _Args>
class ExpressionVisitor
    : public Visitor<VirtualExpression, ExpressionType,
    int(TExpressionLast), _Return, _Args...>
{
public:

  typedef Visitor<VirtualExpression, ExpressionType,
      int(TExpressionLast), _Return, _Args...> visitor_type ;
  typedef ExpressionVisitor<_Return, _Args...> base_type;

  ExpressionVisitor(visitor_type&& base) : visitor_type(base) {}

  _Return operator ()(VirtualExpression* input, _Args... args) const
  {
    if (debug_expression_visitor)
    {
      std::cout << "Expression: ";
      input->print(std::cout);
      std::cout << std::endl;
    }
    return visitor_type::operator ()(input, args...);
  }
};


} // compilation

#endif // _COMPILATION_EXPRESSION_VISITOR_H_
